﻿namespace NetFx.SMIL.Definitions
{
  using System;
  using System.Text;
  using System.Collections;

  using System.Reflection;
  using System.Reflection.Emit;
  using System.Runtime.InteropServices;

  using System.Diagnostics;
  using System.Diagnostics.CodeAnalysis;
  using System.Diagnostics.SymbolStore;
  using System.Security;
  using System.Security.Permissions;

  using NetFx.MSIL;
  using NetFx.MSIL.Headers;

  [Flags]
  public enum DefiningPhase:uint
  {
    InitDefinition       = 0x00000000,

    AssemblyDefinition   = 0x00000001,
    
    ModuleDefinition     = 0x00000002,

    TypeDefinition       = 0x00000003,
    EnumDefinition       = 0x00000003,

    FieldDefinition      = 0x00000004,
    FieldApplication     = 0x00000005,

    ParameterDefinition  = 0x00000006,
    MethodDefinition     = 0x00000007,

    PropertyDefinition   = 0x00000008,
    EventDefinition      = 0x00000009,

    EventApplication     = 0x80000009,
    PropertyApplication  = 0x80000008,

    MethodApplication    = 0x80000007,

    TypeApplication      = 0x80000003,
    EnumApplication      = 0x80000003,

    ModuleApplication    = 0x80000002,

    AssemblyApplication  = 0x80000001,

    PostDefinition       = 0x80000000,


  }

 
  public abstract class ComplexDefinition:DefinitionHeader
  {
    #region Statics
    public static ComplexDefinition CreateAssemblyDefinition   (string name) 
    {
      return AssemblyDefinition.of(name);
    }
    public static ComplexDefinition CreateModuleDefinition     (string name) 
    {
      return ModuleDefinition.of(name);
    }
    public static ComplexDefinition CreateTypeDefinition       (string name) 
    {
      return TypeDefinition.of(name);
    }
    public static ComplexDefinition CreateEnumDefinition       (string name) 
    {
      return EnumDefinition.of(name);
    }
    public static ComplexDefinition CreateFieldDefinition      (string name) 
    {
      return FieldDefinition.of(name);
    }
    public static ComplexDefinition CreateEventDefinition      (string name) 
    {
      return EventDefinition.of(name);
    }
    public static ComplexDefinition CreatePropertyDefinition   (string name) 
    {
      return PropertyDefinition.of(name);
    }
    public static ComplexDefinition CreateMethodDefinition     (string name) 
    {
      return MethodDefinition.of(name);
    }
    public static ComplexDefinition CreateParameterDefinition  (string name) 
    {
      return ParameterDefinition.of(name);
    }
    public static ComplexDefinition CreateLogicDefinition      (string name) 
    {
      return LogicDefinition.of(name);
    }
    public static ComplexDefinition CreateVaraibleDefinition   (string name)
    {
      return VariableDefinition.of(name);
    }
    public static ComplexDefinition CreateLabelDefinition      (string name)
    {
      return LabelDefinition.of(name);
    }
    #endregion
    #region Fields
    protected DefinitionHeader header = null;
    protected ComplexDefinition container = null;
    protected ArrayList definitions = new ArrayList();
    #endregion
    #region Properties
    public virtual DefinitionHeader Header
    {
      get
      {
        return this.header;
      }
    }
    public virtual ComplexDefinition Container
    {
      get
      {
        return this.container;
      }
    }
    public virtual DefiningPhase InitPhase
    {
      get
      {
        return DefiningPhase.InitDefinition;
      }
    }
    public virtual IList Definitions
    {
      get
      {
        return this.definitions;
      }
    }
    public override bool IsDefined
    {
      get { return this.Header.IsDefined; }
    }
    public override string Name
    {
      get
      {
        return this.Header.Name;
      }
      set
      {
        this.Header.Name = value;
      }
    }
    public override AnyGenerator Generator
    {
      get { return this.Header.Generator; }
    }
    public override DefType GeneratorType
    {
      get { return this.Header.GeneratorType; }
    }
    #endregion
    #region Constructors
    public ComplexDefinition(DefinitionHeader header)
    {
      if (header == null) throw new ArgumentNullException("header can not be null!");
      this.header = header;
    }
    #endregion
    #region Methods
    #region Definition List
    public virtual ComplexDefinition AddDefinition(ComplexDefinition definition)
    {
      this.Definitions.Add(definition);
      return definition;
    }
    public virtual ComplexDefinition RemoveDefinition(string name)
    {
      ComplexDefinition d = this.GetDefinition(name);
      if (d != null)
      {
        this.Definitions.Remove(d);
      }
      return d;
    }
    public virtual ComplexDefinition GetDefinition(string name)
    {
      foreach (ComplexDefinition d in this.Definitions)
      {
        if (d.Name == name)
          return d;
      }
      return null;
    }
    #endregion

    public virtual void Resolve()
    {
      this.Resolve(this.Container);
    }

    public virtual ComplexDefinition ApplyAttributes(DefiningPhase phase)
    {
      if (this.IsCorrectPhase(phase))
      {
        this.ApplyAttributes(this.Generator);
        foreach (ComplexDefinition def in this.Definitions)
        {
          def.ApplyAttributes(phase);
        }
      }
      return this;
    }

    public virtual ComplexDefinition DefineAt(ComplexDefinition container, DefiningPhase phase)
    {
      if (this.IsCorrectPhase(phase))
      {
        this.DefineAt(container.Generator);
        if (!this.IsDefined)
        {
          this.container = container;
          this.DefineAt(container.Generator);
        }
        foreach (ComplexDefinition def in this.Definitions)
        {
          def.DefineAt(this, phase);
        }
      }
      return this;
    }
 
    public override AnyGenerator ApplyAttributes(AnyGenerator generator)
    {
      return this.Header.ApplyAttributes(generator);
    }

    public override AnyGenerator DefineAt(AnyGenerator container)
    {
      return this.Header.DefineAt(container);
    }

    protected virtual bool IsCorrectPhase(DefiningPhase phase)
    {

      return true;
    }
    protected virtual void Resolve(ComplexDefinition container)
    {
    }
    #endregion
  }
}
